﻿using System;
using System.Reflection;
using System.Text;
using System.Globalization;
using System.Linq;
using System.Collections.Generic;

namespace XTrace
{
	partial class XTraceEvent // : IXmlSerializable
	{



		public string Serialize()
		{
			///using (var ms = new MemoryStream())
			//{
			//	_ser.Serialize(ms, this);
			//	var buf = ms.ToArray();
			//	return Encoding.UTF8.GetString(buf, 0, buf.Length);
			//}
			
			var sb = new StringBuilder();
			sb.Append("time=\"");
			sb.Append(_time.ToString("o"));
			sb.Append("\" project=\"");
			sb.Append(_project.Escape());
			sb.Append("\" sourceName=\"");
			sb.Append(_sourceName.Escape());
			sb.Append("\" level=\"");
			sb.Append(_level.ToString());
			sb.Append("\" eventId=\"");
			sb.Append(_eventId.Escape());
			sb.Append("\" additionalInformation=\"");
			sb.Append(_additionalInformation.Escape());
			sb.Append("\" processId=\"");
			sb.Append(_processId.ToString(CultureInfo.InvariantCulture));
			sb.Append("\" processName=\"");
			sb.Append(_processName.Escape());
			sb.Append("\" threadId=\"");
			sb.Append(_threadId.ToString(CultureInfo.InvariantCulture));
			sb.Append("\" threadName=\"");
			sb.Append(_threadName.Escape());
			sb.Append("\" sourceFile=\"");
			sb.Append(_sourceFile.Escape());
			sb.Append("\" nameSpace=\"");
			sb.Append(_nameSpace.Escape());
			sb.Append("\" className=\"");
			sb.Append(_className.Escape());
			sb.Append("\" methodName=\"");
			sb.Append(_methodName.Escape());
			sb.Append("\" lineNumber=\"");
			sb.Append(_lineNumber.ToString(CultureInfo.InvariantCulture));
			sb.Append("\" callStack=\"");
			sb.Append(_callStack.Escape());
			sb.Append("\"");
			return sb.ToString();
		}
		
		//static XmlSerializer _ser = new XmlSerializer(typeof(XTraceEvent));
		
		public static XTraceEvent Deserialize(string data)
		{
			if (data == null)
			{
				throw new ArgumentNullException("data");
			}
			XTraceEvent ev;
			try
			{
				var time = default(DateTime);
				var project = default(string);
				var sourceName = default(string);
				var level = default(XTraceLevel);
				var eventId = default(string);
				var additionalInformation = default(string);
				var processId = default(int);
				var processName = default(string);
				var threadId = default(int);
				var threadName = default(string);
				var sourceFile = default(string);
				var nameSpace = default(string);
				var className = default(string);
				var methodName = default(string);
				var lineNumber = default(int);
				var callStack = default(string);

				int i, j = 0;
				while((i = data.IndexOf('=', j)) > 0)
				{
					var name = data.Substring(j, i - j).Trim();
					var openQuote = data.IndexOf('"', i)+1;
					var closeQuote = data.IndexOf('"', openQuote);
					var val = data.Substring(openQuote, closeQuote - openQuote);
					j = closeQuote+1;
					
					switch(name)
					{
						case "time":
							time = DateTime.Parse(val).ToUniversalTime();
							break;
						case "project":
							project = val.Unescape();
							break;
						case "sourceName":
							sourceName = val.Unescape();
							break;
						case "level":
							level = (XTraceLevel)Enum.Parse(typeof(XTraceLevel), val, true);
							break;
						case "eventId":
							eventId = val.Unescape();
							break;
						case "additionalInformation":
							additionalInformation = val.Unescape();
							break;
						case "processId":
							processId = int.Parse(val, CultureInfo.InvariantCulture);
							break;
						case "processName":
							processName = val.Unescape();
							break;
						case "threadId":
							threadId = int.Parse(val, CultureInfo.InvariantCulture);
							break;
						case "threadName":
							threadName = val.Unescape();
							break;
						case "sourceFile":
							sourceFile = val.Unescape();
							break;
						case "nameSpace":
							nameSpace = val.Unescape();
							break;
						case "className":
							className = val.Unescape();
							break;
						case "methodName":
							methodName = val.Unescape();
							break;
						case "lineNumber":
							lineNumber = int.Parse(val, CultureInfo.InvariantCulture);
							break;
						case "callStack":
							callStack = val.Unescape();
							break;
					}
				}
			
				ev = new XTraceEvent(time, project, sourceName, level, eventId, additionalInformation, processId, processName, threadId, threadName, sourceFile, nameSpace, className, methodName, lineNumber, callStack);
			}catch(Exception ex){
				return new XTraceEvent(ex.ToString());
			}
			ev.DeserializeValidation();
			return ev;
		}

		#region Properties

		readonly DateTime _time;
		public DateTime Time
		{
			get { return _time.ToLocalTime(); }
			//set { _time = value; }
		}
		
		readonly string _project = string.Empty;
		public string Project
		{
			get { return _project; }
			//set { _project = value; }
		}
		
		readonly string _sourceName = string.Empty;
		public string SourceName
		{
			get { return _sourceName; }
			//set { _sourceName = value; }
		}
		
		readonly XTraceLevel _level;
		public XTraceLevel Level
		{
			get { return _level; }
			//set { _level = value; }
		}
		
		readonly string _eventId = string.Empty;
		public string EventId
		{
			get { return _eventId; }
			//set { _eventId = value; }
		}
		
		readonly string _additionalInformation = string.Empty;
		public string AdditionalInformation
		{
			get { return _additionalInformation; }
			//set { _additionalInformation = value; }
		}
		
		readonly int _processId;
		public int ProcessId
		{
			get { return _processId; }
			//set { _processId = value; }
		}
		
		readonly string _processName = string.Empty;
		public string ProcessName
		{
			get { return _processName; }
			//set { _processName = value; }
		}
		
		readonly int _threadId;
		public int ThreadId
		{
			get { return _threadId; }
			//set { _threadId = value; }
		}
		
		readonly string _threadName = string.Empty;
		public string ThreadName
		{
			get { return _threadName; }
			//set { _threadName = value; }
		}
		
		readonly string _sourceFile = string.Empty;
		public string SourceFile
		{
			get { return _sourceFile; }
			//set { _sourceFile = value; }
		}
		
		readonly string _nameSpace = string.Empty;
		public string NameSpace
		{
			get { return _nameSpace; }
			//set { _nameSpace = value; }
		}
		
		readonly string _className = string.Empty;
		public string ClassName
		{
			get { return _className; }
			//set { _className = value; }
		}
		
		readonly string _methodName = string.Empty;
		public string MethodName
		{
			get { return _methodName; }
			//set { _methodName = value; }
		}
		
		readonly int _lineNumber;
		public int LineNumber
		{
			get { return _lineNumber; }
			//set { _lineNumber = value; }
		}
		
		readonly string _callStack = string.Empty;
		public string CallStack
		{
			get { return _callStack; }
			//set { _callStack = value; }
		}
		
		#endregion

		/// <summary>
		/// Deserialize ctor
		/// </summary>
		XTraceEvent(DateTime time, string project, string sourceName, XTraceLevel level, string eventId, string additionalInformation, int processId, string processName, int threadId, string threadName, string sourceFile, string nameSpace, string className, string methodName, int lineNumber, string callStack)
		{
			_time = time;
			_project = project??string.Empty;
			_sourceName = sourceName??string.Empty;
			_level = level;
			_eventId = eventId??string.Empty;
			_additionalInformation = additionalInformation??string.Empty;
			_processId = processId;
			_processName = processName??string.Empty;
			_threadId = threadId;
			_threadName = threadName??string.Empty;
			_sourceFile = sourceFile??string.Empty;
			_nameSpace = nameSpace??string.Empty;
			_className = className??string.Empty;
			_methodName = methodName??string.Empty;
			_lineNumber = lineNumber;
			_callStack = callStack??string.Empty;
		}
		
		internal XTraceEvent(string sourceName, XTraceLevel level, string eventId, string additionalInformation, Assembly assembly)
			: this(level, assembly, eventId)
		{

			_sourceName = sourceName ?? string.Empty;
			_level = level;
			_eventId = eventId ?? string.Empty;
			_additionalInformation = additionalInformation ?? string.Empty;
		}
		
		//public XmlSchema GetSchema()
		//{
		//	return null;
		//}
		
		//public void WriteXml(XmlWriter writer)
		//{
			//writer.WriteAttributeString("time", _time.ToString("o"));
			//writer.WriteAttributeString("project", _project.Escape());
			//writer.WriteAttributeString("sourceName", _sourceName.Escape());
			//writer.WriteAttributeString("level", _level.ToString());
			//writer.WriteAttributeString("eventId", _eventId.Escape());
			//writer.WriteAttributeString("additionalInformation", _additionalInformation.Escape());
			//writer.WriteAttributeString("processId", _processId.ToString(CultureInfo.InvariantCulture));
			//writer.WriteAttributeString("processName", _processName.Escape());
			//writer.WriteAttributeString("threadId", _threadId.ToString(CultureInfo.InvariantCulture));
			//writer.WriteAttributeString("threadName", _threadName.Escape());
			//writer.WriteAttributeString("sourceFile", _sourceFile.Escape());
			//writer.WriteAttributeString("nameSpace", _nameSpace.Escape());
			//writer.WriteAttributeString("className", _className.Escape());
			//writer.WriteAttributeString("methodName", _methodName.Escape());
			//writer.WriteAttributeString("lineNumber", _lineNumber.ToString(CultureInfo.InvariantCulture));
			//writer.WriteAttributeString("callStack", _callStack.Escape());

		//}
		
		//public void ReadXml(XmlReader reader)
		//{
			//_time = DateTime.Parse(reader.GetAttribute("time")).ToUniversalTime();
			//_project = reader.GetAttribute("project").Unescape();
			//_sourceName = reader.GetAttribute("sourceName").Unescape();
			//_level = (XTraceLevel)Enum.Parse(typeof(XTraceLevel), reader.GetAttribute("level"), true);
			//_eventId = reader.GetAttribute("eventId").Unescape();
			//_additionalInformation = reader.GetAttribute("additionalInformation").Unescape();
			//_processId = int.Parse(reader.GetAttribute("processId"), CultureInfo.InvariantCulture);
			//_processName = reader.GetAttribute("processName").Unescape();
			//_threadId = int.Parse(reader.GetAttribute("threadId"), CultureInfo.InvariantCulture);
			//_threadName = reader.GetAttribute("threadName").Unescape();
			//_sourceFile = reader.GetAttribute("sourceFile").Unescape();
			//_nameSpace = reader.GetAttribute("nameSpace").Unescape();
			//_className = reader.GetAttribute("className").Unescape();
			//_methodName = reader.GetAttribute("methodName").Unescape();
			//_lineNumber = int.Parse(reader.GetAttribute("lineNumber"), CultureInfo.InvariantCulture);
			//_callStack = reader.GetAttribute("callStack").Unescape();
		//}
	
		public string Format(string format)
		{
			return string.Format(CultureInfo.InvariantCulture, format, _time, _project, _sourceName, _level, _eventId, _additionalInformation, _processId, _processName, _threadId, _threadName, _sourceFile, _nameSpace, _className, _methodName, _lineNumber, _callStack);
		}
		
		public static string Columns(string format)
		{
			return string.Format(CultureInfo.InvariantCulture, format, "time", "project", "sourceName", "level", "eventId", "additionalInformation", "processId", "processName", "threadId", "threadName", "sourceFile", "nameSpace", "className", "methodName", "lineNumber", "callStack");
		}
		
		public const string DefaultFormat = "{0:u}\t{1}\t{2}\t{3}\t{4}\t{5}\t{8}\t{9}\t{12}\t{13}\t{14}";
	}
	

}

